package com.gopay.bis.manager.bank.micro;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gopay.bis.common.util.BankLogUtils;
import com.gopay.bis.manager.bank.BankOrderManager;
import com.gopay.common.constants.bank.BisBankBusinessProd;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.cps.manager.order.CpsGeneralMainOrderQueryManager;
import com.gopay.common.domain.bank.BankOrder;
import com.gopay.common.domain.bank.BaseMessage;
import com.gopay.common.domain.bank.wechat.micro.req.MicroPayReqMsg;
import com.gopay.common.domain.bank.wechat.micro.req.MicroQueryReqMsg;
import com.gopay.common.domain.bank.wechat.micro.req.MicroRefundQueryReqMsg;
import com.gopay.common.domain.bank.wechat.micro.req.MicroRefundReqMsg;
import com.gopay.common.domain.bank.wechat.micro.req.MicroReverseReqMsg;
import com.gopay.common.domain.bank.wechat.micro.res.MicroPayResMsg;
import com.gopay.common.domain.bank.wechat.micro.res.MicroQueryResMsg;
import com.gopay.common.domain.bank.wechat.micro.res.MicroRefundQueryResMsg;
import com.gopay.common.domain.bank.wechat.micro.res.MicroRefundResMsg;
import com.gopay.common.domain.bank.wechat.micro.res.MicroReverseResMsg;
import com.gopay.common.domain.cps.CpsGenMainOrder;
import com.gopay.common.exception.GopayException;
import com.gopay.common.util.DateUtils;
import com.gopay.remote.bank.businesses.MicroPayService;
import com.ibm.icu.util.Calendar;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.naming.NoNameCoder;
import com.thoughtworks.xstream.io.xml.DomDriver;

/** 
 * 小额免密支付 manager类
 * @ClassName: MicroPayManager 
 * @author w_jiqing 
 * @date 2017年5月22日 下午3:33:24  
 */ 
public class MicroPayManager {
    
    private static Logger logger = LoggerFactory.getLogger(MicroPayManager.class);
    
    @Resource(name = "microPayConfig")
    private Map<String, String> microPayConfig;
    
    @Resource(name = "microPayServiceClient")
    private MicroPayService microPayServiceClient;
    
    @Resource(name = "bankOrderManager")
    private BankOrderManager bankOrderManager;
    
    @Resource(name = "cpsGeneralMainOrderQueryManager")
    private CpsGeneralMainOrderQueryManager mainOrderQuery;
    
    private static long seed = 0;
    
    public Object payment(BaseMessage msg)throws GopayException{
        MicroPayResMsg resMessage = new MicroPayResMsg();
        try{
            MicroPayReqMsg message = (MicroPayReqMsg) msg;
            message.setService(microPayConfig.get("MICRO.PAY.SERVICE"));
            message.setVersion(microPayConfig.get("MICRO.PAY.VERSION"));
            message.setCharset(microPayConfig.get("MICRO.PAY.CHARSET"));
            message.setSign_type(microPayConfig.get("MICRO.PAY.SIGN.TYPE"));
            message.setMch_id(message.getMerID());
            message.setCustomerID("");
            message.setOut_trade_no(message.getBankOrderId());
            //设备号
            //message.setDevice_info(message.getDeviceInfo());
            //商品描述
            message.setBody(message.getGoodsBody());
            message.setTotal_fee(formatInt(message.getAmount()));
            //终端 IP
            message.setMch_create_ip(message.getMchCreateIp());
            message.setAuth_code(message.getAuthCode());
            //订单生成时间
            message.setTime_start(DateUtils.format(new Date()));
            //订单超时时间  创建时间后退6分钟
            message.setTime_expire(DateUtils.format(DateUtils.add(new Date(), Calendar.MINUTE, 6)));
            //随机字符串
            message.setNonce_str(creatSerialNumber(20));
            message.setPlainMessage(buildSignPlain(message));
            BankLogUtils.printMicroPayManagerSignSendLog(message);
            resMessage = (MicroPayResMsg) microPayServiceClient.payment(message);
            resMessage.setOutStlmCd(message.getBank());
            BankLogUtils.printMicroPayManagerSignReturnLog(resMessage);
        }catch (Exception e) {
            logger.info(e.getMessage());
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E7025,e);
        }
        return resMessage;
        
    }
    
    
    public Object orderQuery(BaseMessage obj) throws GopayException {
        MicroQueryResMsg resMessage = new MicroQueryResMsg();
        try{
            MicroQueryReqMsg message = (MicroQueryReqMsg) obj;
            message.setService(microPayConfig.get("MICRO.QUERY.SERVICE"));
            message.setVersion(microPayConfig.get("MICRO.PAY.VERSION"));
            message.setCharset(microPayConfig.get("MICRO.PAY.CHARSET"));
            message.setSign_type(microPayConfig.get("MICRO.PAY.SIGN.TYPE"));
            message.setMch_id(message.getMerID());
            //冲正交易上送冲正原银行订单号
            if(BisBankBusinessProd._26.value.equals(message.getBankBusProd().value)){
                message.setOut_trade_no(message.getCzOriBankOrderId());
            }else{
                message.setOut_trade_no(message.getBankOrderId());
            }
            
            //随机字符串
            message.setNonce_str(creatSerialNumber(20));
            message.setPlainMessage(buildSignPlain(message));
            //后期修改
            BankLogUtils.printMicroPayManagerQuerySendLog(message);
            resMessage=(MicroQueryResMsg) microPayServiceClient.queryOrder(message);
            resMessage.setBank(message.getBank());
            BankLogUtils.printMicroPayManagerQueryReturnLog(resMessage);
        }catch (Exception e) {
            logger.info(e.getMessage());
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E7027, e);
        }
        return resMessage;   
        
    }
    public Object reverse(BaseMessage obj) throws GopayException {
        MicroReverseResMsg resMessage = new MicroReverseResMsg();
        try{
            MicroReverseReqMsg message = (MicroReverseReqMsg) obj;
            message.setService(microPayConfig.get("MICRO.REVERSE.SERVICE"));
            message.setVersion(microPayConfig.get("MICRO.PAY.VERSION"));
            message.setCharset(microPayConfig.get("MICRO.PAY.CHARSET"));
            message.setSign_type(microPayConfig.get("MICRO.PAY.SIGN.TYPE"));
            message.setMch_id(message.getMerID());
            message.setOut_trade_no(message.getCzOriBankOrderId());
            //随机字符串
            message.setNonce_str(creatSerialNumber(20));
            message.setPlainMessage(buildSignPlain(message));
            BankLogUtils.printMicroPayManagerReverseSendLog(message);
            resMessage = (MicroReverseResMsg) microPayServiceClient.reverse(message);
            resMessage.setBank(message.getBank());
            BankLogUtils.printMicroPayManagerReverseReturnLog(resMessage);
        }catch (Exception e) {
            logger.info(e.getMessage());
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E1181, e);
        }
        return resMessage;
        
    }
    public Object refund(BaseMessage obj) throws GopayException {
        MicroRefundResMsg refundRes = new MicroRefundResMsg();
        try{
            MicroRefundReqMsg message = (MicroRefundReqMsg) obj;
            message.setService(microPayConfig.get("MICRO.REFUND.SERVICE"));
            message.setVersion(microPayConfig.get("MICRO.PAY.VERSION"));
            message.setCharset(microPayConfig.get("MICRO.PAY.CHARSET"));
            message.setSign_type(microPayConfig.get("MICRO.PAY.SIGN.TYPE"));
            message.setMch_id(message.getMerID());
            //商户订单号
            message.setOut_trade_no(message.getTkOriBankOrderId());
            
            //商户退款单号 
            message.setOut_refund_no(message.getBankOrderId());
            //总金额
            message.setTotal_fee(formatInt(message.getTkOriAmount()));
            //退款金额
            message.setRefund_fee(formatInt(message.getAmount()));
            message.setOp_user_id(message.getMerID());
            //退款渠道  ORIGINAL-原路退款，默认BALANCE-余额
            message.setRefund_channel("ORIGINAL");            
            //随机字符串
            message.setNonce_str(creatSerialNumber(20));
            message.setPlainMessage(buildSignPlain(message));
            BankLogUtils.printMicroPayManagerRefundSendLog(message);
            refundRes= (MicroRefundResMsg) microPayServiceClient.refund(message);
            refundRes.setBank(message.getOutStlmCd());
            BankLogUtils.printMicroPayManagerRefundReturnLog(refundRes);
        }catch (Exception e) {
            logger.info(e.getMessage());
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6087, e);
        }
        return refundRes;
        
    }
    
    public Object refundQuery (BaseMessage obj) throws GopayException {
        MicroRefundQueryResMsg refQueRes = new MicroRefundQueryResMsg();
        try{
            MicroRefundQueryReqMsg message = (MicroRefundQueryReqMsg) obj;
            message.setService(microPayConfig.get("MICRO.REFUND.QUERY.SERVICE"));
            message.setVersion(microPayConfig.get("MICRO.PAY.VERSION"));
            message.setCharset(microPayConfig.get("MICRO.PAY.CHARSET"));
            message.setSign_type(microPayConfig.get("MICRO.PAY.SIGN.TYPE"));
            message.setMch_id(message.getMerID());
            //商户订单号 
            message.setOut_trade_no(message.getTkOriBankOrderId());
            //商户退款单号
            message.setOut_refund_no(message.getBankOrderId());
            message.setNonce_str(creatSerialNumber(20));
            message.setPlainMessage(buildSignPlain(message));
            BankLogUtils.printMicroPayManagerRefundQuerySendLog(message);
            refQueRes = (MicroRefundQueryResMsg) microPayServiceClient.refundQuery(message);
            refQueRes.setBank(message.getBank());
            BankLogUtils.printMicroPayManagerRefundQueryReturnLog(refQueRes);
        }catch (Exception e) {
            logger.info(e.getMessage());
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6063, e);
        }
        return refQueRes;
        
    }
    
    /** 
     * @Description: 将金额格转为int型
     * @param num
     * @return 
     * @author w_jiqing 
     */
    private int formatInt(BigDecimal num){
        
        int intAmount = num.multiply(new BigDecimal(100)).intValue();
        return intAmount;

         
    }
    
    /**
     * @Description: 生成随机字符串
     * @param length
     * @return
     * @author w_jiqing
     */
    public static String creatSerialNumber(int length) {
        byte[] randomSerial = new byte[length];
        String charactors = "123456789abcdefghigklmnopkrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ";
        int charSetLength = charactors.length();
        seed = seed ^ System.currentTimeMillis();
        java.util.Random randomNumber = new java.util.Random(seed);

        for (int i = 0; i < length; i++) {
            randomNumber.setSeed(seed);
            int j = (int) (randomNumber.nextFloat() * charSetLength);
            randomSerial[i] = (byte) charactors.charAt(j);
            seed = seed ^ randomNumber.nextInt();
        }
        return (new String(randomSerial));
    }
    
    /** 
     * @Description: 拼装加密报文
     * @param obj
     * @return
     * @throws Exception 
     * @author w_jiqing 
     */
        public String buildSignPlain(Object obj) throws Exception{
            // 去掉多一个下划线的问题
            XStream xstream = new XStream(new DomDriver("UTF-8", new NoNameCoder()));
            xstream.processAnnotations(obj.getClass());
            return xstream.toXML(obj);       
        }
    
}

    
    


